package com.chagee.channel.server.event.facade;

import com.chagee.base.utils.SoaResponse;
import com.chagee.base.utils.SoaUtil;
import com.chagee.channel.api.bo.FileBo;
import com.chagee.channel.api.service.ICosServiceApi;
import com.chagee.channel.common.exception.BizErrorCode;
import com.qcloud.cos.COSClient;
import com.qcloud.cos.ClientConfig;
import com.qcloud.cos.auth.BasicSessionCredentials;
import com.qcloud.cos.auth.COSCredentials;
import com.qcloud.cos.http.HttpMethodName;
import com.qcloud.cos.http.HttpProtocol;
import com.qcloud.cos.model.ObjectMetadata;
import com.qcloud.cos.model.PutObjectRequest;
import com.qcloud.cos.model.PutObjectResult;
import com.qcloud.cos.region.Region;
import com.qcloud.cos.utils.Jackson;
import com.tencent.cloud.CosStsClient;
import com.tencent.cloud.Policy;
import com.tencent.cloud.Response;
import com.tencent.cloud.Statement;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;
import java.util.concurrent.ThreadPoolExecutor;
import javax.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

@Service
@Slf4j
public class CosServiceRpcImpl implements ICosServiceApi {


    @Value("${qcloud.cos.accessId}")
    private String QCCLOUD_SECRETID;
    @Value("${qcloud.cos.accessSecret}")
    private String QCCLOUD_SECRETKEY;
    @Value("${qcloud.cos.id}")
    private String QCCLOUD_ID;
    @Value("${qcloud.cos.bucket}")
    private String COS_BUCKET;
    @Value("${qcloud.cos.region}")
    private String COS_REGION;
    @Value("${qcloud.cos.prefix}")
    private String COS_DIR_PREFIX;
    @Value("${qcloud.cos.time:3}")
    private String COS_EXPIRE;
    @Resource(name = "cosSyncExecutor")
    private ThreadPoolExecutor threadPoolExecutor;

    private static final String qcImgParam = "&ci-process=snapshot&width=80&height=80&time=";
    @Override
    public SoaResponse<String, Void> getVideoImg(FileBo file) {
        log.info("CosServiceRpcImpl getVideoImg FilePath = {}", file.getFilePath());
        return SoaUtil.error(BizErrorCode.REQUEST_VALID_FAILED.getErrorCode(), BizErrorCode.REQUEST_VALID_FAILED.getErrorMsg(), null);
        /*
        if (file.getFilePath().contains(".aliyuncs.com")) {
            String imgParam = "?x-oss-process=video/snapshot,t_"+COS_EXPIRE+"000,f_jpg,w_80,h_80,m_fast";
            return SoaUtil.ok(file.getFilePath()+imgParam);
        } else if (file.getFilePath().contains(".myqcloud.com/")) {
            COSClient cosClient = createCOSClientTemp();
            try {
                String[] split = file.getFilePath().split(".myqcloud.com/");
                String key = split[1];
                String imgKey = COS_DIR_PREFIX+key.split("\\.")[0]+".jpg";
                // 生成图片地址
                Date expirationDate = new Date(System.currentTimeMillis() + 60 * 60 * 1000);
                // 填写本次请求的参数，需与实际请求相同，能够防止用户篡改此签名的 HTTP 请求的参数
                Map<String, String> params = new HashMap<String, String>();
                // 填写本次请求的头部，需与实际请求相同，能够防止用户篡改此签名的 HTTP 请求的头部
                Map<String, String> headers = new HashMap<String, String>();
                URL imgUrl = cosClient.generatePresignedUrl(COS_BUCKET, imgKey, expirationDate, HttpMethodName.GET, headers, params);
                cosClient.shutdown();
                threadPoolExecutor.execute(() -> handleImg(file.getFilePath(), key, imgKey));
                return SoaUtil.ok(imgUrl.toString());
            } catch (Exception e) {
                log.error("file {} getVideoImg met error ", file.getFilePath(), e);
                throw new BizException(BizErrorCode.FAIL, "获取失败");
            }
        }
        return SoaUtil.error(BizErrorCode.REQUEST_VALID_FAILED.getErrorCode(), "未知来源的文件", null);*/
    }

    private void handleImg(String filePath,String videoKey, String imgKey) {
        InputStream input = null;
        InputStream inputImg = null;
        COSClient cosClient = createCOSClientTemp();
        try {
            // 图片是否存在
            boolean objectExist = cosClient.doesObjectExist(COS_BUCKET, imgKey);
            if (!objectExist) {
                // 上传视频
                input = new URL(filePath).openStream();
                ObjectMetadata objectMetadata = new ObjectMetadata();
    //			objectMetadata.setSecurityToken(map.get("sessionToken"));
                PutObjectRequest putObjectRequest = new PutObjectRequest(COS_BUCKET, videoKey, input, objectMetadata);
                PutObjectResult putObjectResult = cosClient.putObject(putObjectRequest);
                log.info("putObjectResult = {}", putObjectResult.toString());
                Date expirationDate = new Date(System.currentTimeMillis() + 60 * 60 * 1000);
                Map<String, String> params = new HashMap<String, String>();
                Map<String, String> headers = new HashMap<String, String>();

                // 视频地址
                URL url = cosClient.generatePresignedUrl(COS_BUCKET, videoKey, expirationDate, HttpMethodName.GET, headers, params);
                // 上传图片
                String videoImgUrl = url.toString()+qcImgParam+COS_EXPIRE;
                inputImg = new URL(videoImgUrl).openStream();
                PutObjectRequest putImgRequest = new PutObjectRequest(COS_BUCKET, imgKey, inputImg, objectMetadata);
                PutObjectResult putImgResult = cosClient.putObject(putImgRequest);
                // 删除视频
                cosClient.deleteObject(COS_BUCKET, videoKey);
            }
        } catch (Exception e) {
            log.error("handleImg met error s: ", e);
        } finally {
            if (null != input) {
                try {
                    input.close();
                } catch (IOException e) {
                    log.error("handleImg met IOException error e: ", e);
                }
            }
            if (null != inputImg) {
                try {
                    inputImg.close();
                } catch (IOException e) {
                    log.error("handleImg met IOException error e: ", e);
                }
            }
            cosClient.shutdown();
        }
    }

    private  Map<String, String> tempKey() {
        TreeMap<String, Object> config = new TreeMap<String, Object>();
        try {
            //这里的 SecretId 和 SecretKey 代表了用于申请临时密钥的永久身份（主账号、子账号等），子账号需要具有操作存储桶的权限。
            config.put("secretId", QCCLOUD_SECRETID);
            // 替换为您的云 api 密钥 SecretKey
            config.put("secretKey", QCCLOUD_SECRETKEY);

            // 初始化 policy
            Policy policy = new Policy();
            // 临时密钥有效时长，单位是秒，默认 1800 秒，目前主账号最长 2 小时（即 7200 秒），子账号最长 36 小时（即 129600）秒
            config.put("durationSeconds", 7200);
            // 换成您的 bucket
            config.put("bucket", COS_BUCKET);
            // 换成 bucket 所在地区
            config.put("region", COS_REGION);

            // 开始构建一条 statement
            Statement statement = new Statement();
            // 声明设置的结果是允许操作
            statement.setEffect("allow");
            /**
             * 密钥的权限列表。必须在这里指定本次临时密钥所需要的权限。
             * 权限列表请参见 https://cloud.tencent.com/document/product/436/31923
             * 规则为 {project}:{interfaceName}
             * project : 产品缩写  cos相关授权为值为cos,数据万象(数据处理)相关授权值为ci
             * 授权所有接口用*表示，例如 cos:*,ci:*
             * 添加一批操作权限 :
             */
            statement.addActions(new String[]{
                    "cos:*",
//				"cos:PutObject",
//				"cos:GetBucket",
//				"cos:DeleteObject",
//				// 表单上传、小程序上传
//				"cos:PostObject",
//				// 分块上传
//				"cos:InitiateMultipartUpload",
//				"cos:ListMultipartUploads",
//				"cos:ListParts",
//				"cos:UploadPart",
//				"cos:CompleteMultipartUpload",
//				"ci:generatePresignedUrl",

                    // 处理相关接口一般为数据万象产品 权限中以ci开头
                    // 创建媒体处理任务
//				"ci:CreateMediaJobs",
//				"ci:GenerateSnapshot",
//				// 文件压缩
//				"ci:CreateFileProcessJobs"
                    "ci:*"
            });

            /**
             * 这里改成允许的路径前缀，可以根据自己网站的用户登录态判断允许上传的具体路径
             * 资源表达式规则分对象存储(cos)和数据万象(ci)两种
             * 数据处理、审核相关接口需要授予ci资源权限
             *  cos : qcs::cos:{region}:uid/{appid}:{bucket}/{path}
             *  ci  : qcs::ci:{region}:uid/{appid}:bucket/{bucket}/{path}
             * 列举几种典型的{path}授权场景：
             * 1、允许访问所有对象："*"
             * 2、允许访问指定的对象："a/a1.txt", "b/b1.txt"
             * 3、允许访问指定前缀的对象："a*", "a/*", "b/*"
             *  如果填写了“*”，将允许用户访问所有资源；除非业务需要，否则请按照最小权限原则授予用户相应的访问权限范围。
             *
             * 示例：授权examplebucket-1250000000 bucket目录下的所有资源给cos和ci 授权两条Resource
             */
            statement.addResources(new String[]{
                    "qcs::cos:"+COS_BUCKET+":uid/"+QCCLOUD_ID+":"+COS_BUCKET+"/*",
                    "qcs::ci:ap-"+COS_BUCKET+":uid/"+QCCLOUD_ID+":bucket/"+COS_BUCKET+"/*"});

            // 把一条 statement 添加到 policy
            // 可以添加多条
            policy.addStatement(statement);
            // 将 Policy 示例转化成 String，可以使用任何 json 转化方式，这里是本 SDK 自带的推荐方式
            config.put("policy", Jackson.toJsonPrettyString(policy));

            Response response = CosStsClient.getCredential(config);
            HashMap<String, String> map = new HashMap<>();
            map.put("tmpSecretId", response.credentials.tmpSecretId);
            map.put("tmpSecretKey", response.credentials.tmpSecretKey);
            map.put("sessionToken", response.credentials.sessionToken);
            return map;
        } catch (Exception e) {
            e.printStackTrace();
            throw new IllegalArgumentException("createCOSClientTemp tempKey no valid secret !");
        }
    }

    // 创建 COSClient 实例，这个实例用来后续调用请求
    private COSClient createCOSClientTemp() {

        Map<String, String> map = tempKey();
        // 这里需要已经获取到临时密钥的结果。
        // 临时密钥的生成参见 https://cloud.tencent.com/document/product/436/14048#cos-sts-sdk
        String tmpSecretId = map.get("tmpSecretId");
        String tmpSecretKey = map.get("tmpSecretKey");
        String sessionToken = map.get("sessionToken");

        COSCredentials cred = new BasicSessionCredentials(tmpSecretId, tmpSecretKey, sessionToken);

        // ClientConfig 中包含了后续请求 COS 的客户端设置：
        ClientConfig clientConfig = new ClientConfig();

        // 设置 bucket 的地域
        // COS_REGION 请参见 https://cloud.tencent.com/document/product/436/6224
        clientConfig.setRegion(new Region(COS_REGION));

        // 设置请求协议, http 或者 https
        // 5.6.53 及更低的版本，建议设置使用 https 协议
        // 5.6.54 及更高版本，默认使用了 https
        clientConfig.setHttpProtocol(HttpProtocol.https);
        // 设置 socket 读取超时，默认 30s
        clientConfig.setSocketTimeout(30*1000);
        // 设置建立连接超时，默认 30s
        clientConfig.setConnectionTimeout(30*1000);

        // 生成 cos 客户端。
        return new COSClient(cred, clientConfig);
    }

}
